package top.chukongxiang.project.base.utils;


import lombok.AllArgsConstructor;
import lombok.Data;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;

public class SqlUtils {


    @Data
    @AllArgsConstructor
    public static class Entry{
        private String key;
        private String prefix;
        private Class<?> clazz;
    }

    public static Entry entry(String key, String prefix, Class<?> tClass){
        return new Entry(key,prefix,tClass);
    }


    /**
     * 多表查询返回的Map转为对象
     * 1.实体类class中必须包含无参构造
     * 2.实体类中应该包含查询到的字段的set方法
     * 3.entry中的class实体的set方法必须是驼峰式
     * 4.不支持基本类型boolean（支持包装类型Boolean）
     * @param data 多表查询返回的数据
     * @param entries 要转换的对象
     * @return
     */
    public static List<Map<String,Object>> moreTable(List<Map<String,Object>> data, Entry... entries)  {
        List<Map<String,Object>> list = new ArrayList<>();
        //拷贝原数据
        List<Map<String,Object>> copyData = ArrayUtils.deepCopy(data);
        Iterator<Map<String, Object>> iterator = copyData.iterator();
        while(iterator.hasNext()){
            //得到每一行记录
            Map<String, Object> next = iterator.next();
            Map<String,Object> lineData = new HashMap<>();
            for(Entry entry:entries){
                Object o = null;
                try {
                    o = entry.getClazz().newInstance();
                } catch (Exception e) {
                    System.out.println("不能实例化："+o.getClass().getName()+" (该类可能没有无参构造)");
                    continue;
                }
                for(String column:next.keySet()){
                    if(column.startsWith(entry.prefix)){
                        if(column.length()==entry.prefix.length()) {
                            continue;
                        }
                        String methodName = column.substring(entry.prefix.length());
                        if(methodName.charAt(0)>96 && methodName.charAt(0)<123){
                            //如果开头是小写，转换成大写
                            methodName = "set"+(char)(methodName.charAt(0)-32) + methodName.substring(1);

                        }
                        try {
                            //执行方法
                            Method declaredMethod = o.getClass().getDeclaredMethod(methodName, next.get(column).getClass());
                            if(declaredMethod!=null) {
                                try {
                                    declaredMethod.invoke(o,next.get(column));
                                } catch (Exception e) {
                                    System.out.println("执行方法时发生异常（类型不匹配或方法抛出了异常）");
                                    continue;
                                }
                            }
                        } catch (NoSuchMethodException e) {
                            System.out.println("没有找到"+methodName+"方法");
                            continue;
                        }
                    }
                }
                lineData.put(entry.getKey(),o);
            }
            list.add(lineData);
        }
        return list;
    }


    public static <T> List<T> refSqlModel(ResultSet rs, Class<T> clazz) throws SQLException {
        Field[] fields = clazz.getDeclaredFields();
        List<T> list = new ArrayList<>();
        while (rs.next()) {
            T t;
            try {
                t = clazz.newInstance();
            } catch (InstantiationException | IllegalAccessException e) {
                System.err.println(clazz.getName() + "缺少无参构造");
                break;
            }
            for (Field field : fields) {
                String setMethodName = "set" + (field.getName().charAt(0)+"").toUpperCase() + field.getName().substring(1);
                Method method;
                try {
                    method = clazz.getDeclaredMethod(setMethodName, field.getType());
                } catch (NoSuchMethodException | SecurityException e) {
                    System.out.println(setMethodName + "方法不存在");
                    continue;
                }
                try {
                    method.invoke(t, rs.getObject(field.getName()));
                } catch (IllegalAccessException e) {
                    System.err.println(field.getName() + "数据库类型与实体类属性类型不匹配");
                } catch (InvocationTargetException e) {
                    System.err.println("set方法参数错误");
                }
            }
            list.add(t);
        }
        return list;
    }

}
